#include "messageshowarea.h"
#include "debug.h"
#include "mainwidget.h"
#include "model/datacenter.h"
#include "speechrecorder.h"
#include "toast.h"
#include "userinfowidget.h"
#include "utils/widgetuitl.hpp"
#include "utils/log.hpp"

#include <QScrollBar>
#include <QEvent>
#include <QVBoxLayout>
#include <QPushButton>
#include <QFontMetrics>
#include <QPainter>
#include <QPainterPath>
#include <QTimer>
#include <QBuffer>
#include <QImageReader>
#include <QEnterEvent>
#include <QFileDialog>
#include <QMenu>

MessageShowArea::MessageShowArea()
{
    // 1.创建滚动区
    scrollArea = utils::WidgetUtil::createQScrollArea();
    scrollArea->viewport()->setStyleSheet("background-color: rgb(245, 245, 245);");     // 设置视口背景色

    // 2.为MessageShowArea创建一个布局管理器, 用于存放滚动区
    QVBoxLayout* mainLayout = new QVBoxLayout();
    mainLayout->setContentsMargins(0, 0, 0, 0);
    mainLayout->setSpacing(0);
    mainLayout->addWidget(scrollArea);
    this->setLayout(mainLayout);

    // 3.创建container, 作为滚动条的参照窗口
    container = new QWidget();
    scrollArea->setWidget(container);

    // 4.给container创建布局管理器
    QVBoxLayout* contentLayout = new QVBoxLayout();
    contentLayout->setSpacing(0);
    contentLayout->setContentsMargins(0, 0, 0, 0);
    container->setLayout(contentLayout);

#if TEST_UI
    // 添加测试数据
    for(int i = 1; i <= 30; ++i) {
        model::UserInfo userInfo;
        userInfo.userId = QString::number(i);
        userInfo.description = "我办事你闹心";
        userInfo.phone = "16156446131";
        userInfo.nickname = "小美" + QString::number(i);
        userInfo.avatar = QIcon(":/resource/image/girl.jpg");
        Message message = Message::makeMessage(model::TEXT_TYPE, "", userInfo, "this is a test", "");
        addMessage(true, message);
    }
    model::UserInfo userInfo;
    userInfo.userId = QString::number(31);
    userInfo.description = "我办事你闹心";
    userInfo.phone = "12123136131";
    userInfo.nickname = "小美" + QString::number(31);
    userInfo.avatar = QIcon(":/resource/image/girl.jpg");
    Message message = Message::makeMessage(model::TEXT_TYPE, "", userInfo, "this is a testthis is a testthis is a test this is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a testthis is a test", "");
    addMessage(0, message);
#endif
}

void MessageShowArea::addMessage(bool isLeft, const Message& message)
{
    MessageItem* messageItem =  MessageItem::makeMessageItem(isLeft, message);
    container->layout()->addWidget(messageItem);
}

void MessageShowArea::addFrontMessage(bool isLeft, const Message& message)
{
    MessageItem* messageItem = MessageItem::makeMessageItem(isLeft, message);
    QVBoxLayout* layout = dynamic_cast<QVBoxLayout*>(container->layout());
    layout->insertWidget(0, messageItem);
}

void MessageShowArea::clear()
{
    QLayout* layout = container->layout();
    for(int i = layout->count() - 1; i >= 0; --i) {
        QLayoutItem* item = layout->takeAt(i);
        if(item && item->widget()) {
            delete item->widget();
        }
    }
}

void MessageShowArea::scrollToEndLater(int laterTime)
{
    QTimer* timer = new QTimer();
    connect(timer, &QTimer::timeout, this, [=](){
        int maxVal = this->scrollArea->verticalScrollBar()->maximum();
        this->scrollArea->verticalScrollBar()->setValue(maxVal);

        timer->stop();
        timer->deleteLater();
    });
    timer->start(laterTime);
}

MessageItem::MessageItem(bool isLeft) : isLeft(isLeft)
{

}

MessageItem* MessageItem::makeMessageItem(bool isLeft, const Message& message)
{
    // 1. 创建消息对象 布局管理器
    MessageItem* messageItem = new MessageItem(isLeft);
    QGridLayout* layout = new QGridLayout();
    layout->setSpacing(5);
    layout->setContentsMargins(30, 10, 30, 0);
    messageItem->setMinimumHeight(100);
    messageItem->setLayout(layout);

    // 2. 创建头像
    QPushButton* avatarBtn = new QPushButton();
    avatarBtn->setFixedSize(40, 40);
    avatarBtn->setIconSize({40, 40});
    avatarBtn->setIcon(message.sender.avatar);
    avatarBtn->setStyleSheet("QPushButton { border: none; } ");
    if(isLeft) {
        layout->addWidget(avatarBtn, 0, 0, 2, 1, Qt::AlignTop | Qt::AlignLeft);
    } else {
        layout->addWidget(avatarBtn, 0, 1, 2, 1, Qt::AlignTop | Qt::AlignLeft);
    }

    // 3. 创建名字、时间
    QLabel* nameLabel = new QLabel();
    nameLabel->setContentsMargins(5, 0, 5, 0);      // 补充名字|时间与头像的边距
    nameLabel->setText(message.sender.nickname + " | " + message.time);
    nameLabel->setAlignment(Qt::AlignBottom);
    nameLabel->setStyleSheet("QLabel { font-size: 12px; color: rgb(178, 178, 178); }");
    if(isLeft) {
        layout->addWidget(nameLabel, 0, 1);
    } else {
        layout->addWidget(nameLabel, 0, 0, Qt::AlignRight);
    }

    // 4. 根据消息类型构建具象消息体
    QWidget* contentWidget = nullptr;
    switch (message.messageType)
    {
    case model::MessageType::TEXT_TYPE:
        contentWidget = makeTextMessageItem(message.content, isLeft);
        break;
    case model::MessageType::IMAGE_TYPE:
        contentWidget = makeImageMessageItem(message.fileId, message.content, isLeft);
        break;
    case model::MessageType::FILE_TYPE:
        contentWidget = makeFileMessageItem(message.fileId, message.content, isLeft, message.fileName);
        break;
    case model::MessageType::SPEECH_TYPE:
        contentWidget = makeSoundMessageItem(message.fileId, message.content, isLeft);
        break;
    default:
        LOG(LL_ERROR, "error message type: {}", message.messageType);
        break;
    }
    if (isLeft) {
        layout->addWidget(contentWidget, 1, 1);
    } else {
        layout->addWidget(contentWidget, 1, 0);
    }

    // 关联头像点击事件信号槽 -- 用户信息卡片
    connect(avatarBtn, &QPushButton::clicked, messageItem, [=](){
        UserInfoWidget* userInfo = new UserInfoWidget(MainWidget::getInstance(), message.sender);
        userInfo->exec();
    });

    if(!isLeft) {
        model::DataCenter* dataCenter = model::DataCenter::getInstance();

        // 消息展示区 -- 修改昵称同步
        connect(dataCenter, &model::DataCenter::changeNicknameDone, messageItem, [=](){
            nameLabel->setText(dataCenter->getSelfInfo()->nickname + " | " + message.time);
        });

        // 修改头像同步
        connect(dataCenter, &model::DataCenter::changeAvatarDone, messageItem, [=](){
            avatarBtn->setIcon(dataCenter->getSelfInfo()->avatar);
        });
    }

    return messageItem;
}

QWidget* MessageItem::makeTextMessageItem(const QByteArray& content, bool isLeft)
{
    MessageContentLabel* messageContentLabel = new MessageContentLabel(content, isLeft);
    return messageContentLabel;
}

QWidget* MessageItem::makeImageMessageItem(const QString& fileId, const QByteArray& content, bool isLeft)
{
    MessageImageLabel* messageImageLabel = new MessageImageLabel(fileId, content, isLeft);
    return messageImageLabel;
}

QWidget* MessageItem::makeFileMessageItem(const QString& fileId, const QByteArray& content, bool isLeft, const QString& fileName)
{
    MessageFileLabel* messageFileLabel = new MessageFileLabel(fileId, content, fileName, isLeft);
    return messageFileLabel;
}

QWidget* MessageItem::makeSoundMessageItem(const QString& fileId, const QByteArray& content, bool isLeft)
{
    MessageSpeechLabel* messageSpeechLabel = new MessageSpeechLabel(fileId, content, isLeft);
    return messageSpeechLabel;
}


/* ====================================== *
 *           文本消息类接口实现              *
 * ====================================== */
MessageContentLabel::MessageContentLabel(const QString& text, bool isLeft)
    : isLeft(isLeft)
{
    // 设置SizePolicy(不设置则Qt默认按照等宽排列)
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    QFont font;
    font.setFamily("微软雅黑");
    font.setPixelSize(16);

    label = new QLabel(this);
    label->setText(text);
    label->setFont(font);
    label->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
    this->label->setWordWrap(true);     // 自动换行
    this->label->setStyleSheet("QLabel { padding: 0 10px; line-height: 1.2; background-color: transparent; }");
}

void MessageContentLabel::paintEvent(QPaintEvent* event)
{
    (void)event;

    QObject* obj = this->parent();
    if(!obj->isWidgetType()) return;

    // 1-1 设定实际每一行的数据宽度 realLineWidget
    QWidget* parent = dynamic_cast<QWidget*>(obj);
    int realWidget = parent->width() * 0.6;

    QFontMetrics metrics(label->font());
    // 1-2 全部数据所需的宽度
    int textTotalWight = metrics.horizontalAdvance(label->text());
    // 1-3 全部数据 + 内边距 需要的行数
    int needLineCount = (textTotalWight / (realWidget - 40)) + 1;
    if(textTotalWight + 30 < realWidget) {
        // 加上左右边距后还是比设定的最大宽度小, 直接置为实际需要的宽度
        realWidget = textTotalWight + 30;
    }
    // 1-4 根据行数，算出的行高(含边距)
    int realHeight = needLineCount * (label->font().pixelSize() * 1.2) + 20;
    if(needLineCount > 1) realHeight += 10;

    // 2. 绘画消息背景ui
    QPainter painter(this);
    QPainterPath path;
    painter.setRenderHint(QPainter::Antialiasing);      // 设置抗锯齿
    if (isLeft) {
        painter.setPen(QPen(QColor(255, 255, 255)));
        painter.setBrush(QColor(255, 255, 255));

        // 绘画一个矩形: 起始坐标, 绘画的宽度*高度, 圆角的幅度
        painter.drawRoundedRect(10, 0, realWidget, realHeight, 10, 10);
        path.moveTo(10, 15);
        path.lineTo(0, 20);     // 从(10, 15)向(0, 20)画一条线
        path.lineTo(10, 25);    // 从(0, 20)向(10, 25)画一条线
        path.closeSubpath();    // 闭合绘画的图形
        painter.drawPath(path);

        label->setGeometry(10, 0, realWidget, realHeight);   // 正文数据的位置
    } else {
        painter.setPen(QPen(QColor(137, 217, 97)));
        painter.setBrush(QColor(137, 217, 97));

        // 矩形左上角、右上角的横坐标位置
        int leftTopPos = this->width() - realWidget - 10;     // 10宽度留给箭头ui
        int rightTopPos = this->width() - 10;
        painter.drawRoundedRect(leftTopPos, 0, realWidget, realHeight, 10, 10);
        path.moveTo(rightTopPos, 15);
        path.lineTo(rightTopPos + 10, 20);
        path.lineTo(rightTopPos, 25);
        path.closeSubpath();
        painter.drawPath(path);

        label->setGeometry(leftTopPos, 0, realWidget, realHeight);
    }

    // 3. 矫正父元素的高度(需要包含除正文外的其它数据高度)
    parent->setFixedHeight(realHeight + 50);
}


/* ====================================== *
 *           图片消息类接口实现              *
 * ====================================== */
MessageImageLabel::MessageImageLabel(const QString& fileId, const QByteArray& content, bool isLeft)
    : fileId(fileId), content(content), isLeft(isLeft), imageSize({0, 0})
{
    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    imageBtn = new QPushButton(this);
    imageBtn->setStyleSheet("QPushButton { border: none; background-color: white; }");
    imageBtn->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    // 没有正文数据, 需要从服务器获取二进制数据
    if(content.isEmpty()) {
        model::DataCenter* dataCenter = model::DataCenter::getInstance();
        connect(dataCenter, &model::DataCenter::getSingleFileDone, this,  &MessageImageLabel::getSingleFileDoneHandle);
        dataCenter->getSingleFileAsync(fileId);
    } else {
        loadImage(content);
    }
}

void MessageImageLabel::getSingleFileDoneHandle(const QString& fileId, const QByteArray& fileContent)
{
    // 每个图片都连接了该信号槽, 因此需要排除不属于自己图片的那个信号
    if(this->fileId != fileId) {
        return;
    }
    this->loadImage(fileContent);
}

void MessageImageLabel::loadImage(const QByteArray& imageData)
{
    if (imageLoaded) return; // 防止重复加载

    // 1. 使用QImageReader自动处理EXIF旋转, 加载图像
    QBuffer buffer(const_cast<QByteArray*>(&imageData));
    buffer.open(QIODevice::ReadOnly);
    QImageReader reader(&buffer);
    reader.setAutoTransform(true);
    image = reader.read();

    // 2.消息展示区中的图片缩放
    updateImageSize();

    // QImage无法直接生成QIcon, 转成QPixmap
    QPixmap pixmap = QPixmap::fromImage(image.scaled(imageSize.width(), imageSize.height(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
    pixmap.setDevicePixelRatio(this->devicePixelRatioF());
    imageBtn->setFixedSize(imageSize);
    imageBtn->setIconSize(imageSize);
    imageBtn->setIcon(QIcon(pixmap));

    // 等待控件的布局/绘制事件处理完毕再进行调整父窗口高度和按钮位置
    QTimer::singleShot(0, this, [this]() {
        QWidget* parent = dynamic_cast<QWidget*>(this->parent());
        if(parent) {
            parent->setFixedHeight(imageSize.height() + 50);
        }

        // 强制更新布局
        if (parentWidget() && parentWidget()->layout()) {
            parentWidget()->layout()->activate();
        }

        this->updateGeometry();        // 确保使用最新的宽度, 未后续调整位置作保障
        QApplication::processEvents(); // 处理所有待处理事件

        if (isLeft) {
            imageBtn->setGeometry(10, 0, imageSize.width(), imageSize.height());
        } else {
            int leftPos = this->width() - imageSize.width() - 10;
            imageBtn->setGeometry(leftPos, 0, imageSize.width(), imageSize.height());
        }

        MainWidget::getInstance()->getMessageShowArea()->scrollToEndLater(0);
    });

    imageLoaded = true;
}

void MessageImageLabel::updateImageSize()
{
    int minVal = 100, maxVal = 300;
    if(image.width() > image.height()) {
        imageSize.setWidth(maxVal);
        imageSize.setHeight(maxVal * image.height() / image.width());

        if(imageSize.height() < minVal) {
            imageSize.setHeight(minVal);
        }
        if(imageSize.height() > maxVal) {
            imageSize.setHeight(maxVal);
        }
    } else {
        // 与上述推理同理
        imageSize.setHeight(maxVal);
        imageSize.setWidth(maxVal * image.width() / image.height());

        if(imageSize.width() < minVal) {
            imageSize.setWidth(minVal);
        }
        if(imageSize.width() > maxVal) {
            imageSize.setWidth(maxVal);
        }
    }

    qreal dpr = this->devicePixelRatioF();
    imageSize.setWidth(int(imageSize.width() / dpr));
    imageSize.setHeight(int(imageSize.height() / dpr));
}


/* ====================================== *
 *           文件消息类接口实现              *
 * ====================================== */
MessageFileLabel::MessageFileLabel(const QString& fileId, const QByteArray& content, const QString& fileName, bool isLeft)
    : fileId(fileId), fileName(fileName), content(content), isLeft(isLeft), loadContentDone(false)
{
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    QFont font;
    font.setFamily("微软雅黑");
    font.setPixelSize(16);

    label = new QLabel(this);
    label->setText("[文件] " + fileName);
    label->setFont(font);
    label->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
    this->label->setWordWrap(true);     // 自动换行
    this->label->setStyleSheet("QLabel { padding: 0 10px; line-height: 1.2; background-color: transparent; }");

    if(content.isEmpty()) {
        model::DataCenter* dataCenter = model::DataCenter::getInstance();
        connect(dataCenter, &model::DataCenter::getSingleFileDone, this, &MessageFileLabel::getSingleFileDoneHandle);
        dataCenter->getSingleFileAsync(fileId);
    } else {
        this->loadContentDone = true;
    }
}

void MessageFileLabel::paintEvent(QPaintEvent* event)
{
    (void)event;

    QObject* obj = this->parent();
    if(!obj->isWidgetType()) return;

    // 1-1 设定实际每一行的数据宽度 realLineWidget
    QWidget* parent = dynamic_cast<QWidget*>(obj);
    int realWidget = parent->width() * 0.6;

    QFontMetrics metrics(label->font());
    // 1-2 全部数据所需的宽度
    int textTotalWight = metrics.horizontalAdvance(label->text());
    // 1-3 全部数据 + 内边距 需要的行数
    int needLineCount = (textTotalWight / (realWidget - 40)) + 1;
    if(textTotalWight + 30 < realWidget) {
        // 加上左右边距后还是比设定的最大宽度小, 直接置为实际需要的宽度
        realWidget = textTotalWight + 30;
    }
    // 1-4 根据行数，算出的行高(含边距)
    int realHeight = needLineCount * (label->font().pixelSize() * 1.2) + 20;
    if(needLineCount > 1) realHeight += 10;

    // 2. 绘画消息背景ui
    QPainter painter(this);
    QPainterPath path;
    painter.setRenderHint(QPainter::Antialiasing);      // 设置抗锯齿
    if (isLeft) {
        painter.setPen(QPen(QColor(255, 255, 255)));
        painter.setBrush(QColor(255, 255, 255));

        // 绘画一个矩形: 起始坐标, 绘画的宽度*高度, 圆角的幅度
        painter.drawRoundedRect(10, 0, realWidget, realHeight, 10, 10);
        path.moveTo(10, 15);
        path.lineTo(0, 20);     // 从(10, 15)向(0, 20)画一条线
        path.lineTo(10, 25);    // 从(0, 20)向(10, 25)画一条线
        path.closeSubpath();    // 闭合绘画的图形
        painter.drawPath(path);

        label->setGeometry(10, 0, realWidget, realHeight);   // 正文数据的位置
    } else {
        painter.setPen(QPen(QColor(137, 217, 97)));
        painter.setBrush(QColor(137, 217, 97));

        // 矩形左上角、右上角的横坐标位置
        int leftTopPos = this->width() - realWidget - 10;     // 10宽度留给箭头ui
        int rightTopPos = this->width() - 10;
        painter.drawRoundedRect(leftTopPos, 0, realWidget, realHeight, 10, 10);
        path.moveTo(rightTopPos, 15);
        path.lineTo(rightTopPos + 10, 20);
        path.lineTo(rightTopPos, 25);
        path.closeSubpath();
        painter.drawPath(path);

        label->setGeometry(leftTopPos, 0, realWidget, realHeight);
    }

    // 3. 矫正父元素的高度(需要包含除正文外的其它数据高度)
    parent->setFixedHeight(realHeight + 50);
}

void MessageFileLabel::mousePressEvent(QMouseEvent* event)
{
    if(event->button() == Qt::LeftButton) {
        if(!this->loadContentDone) {
            Toast::showMessage("数据尚未加载完毕, 请稍后重试");
            return;
        }
        saveFileToLocal();
    }
}

void MessageFileLabel::getSingleFileDoneHandle(const QString& fileId, const QByteArray& fileContent)
{
    if(this->fileId != fileId) {
        return;
    }
    this->content = fileContent;
    this->loadContentDone = true;
}

void MessageFileLabel::saveFileToLocal()
{
    QString filePath = QFileDialog::getSaveFileName(this, "另存为", QDir::homePath(), "*");
    if(filePath.isEmpty()) {
        return;
    }
    utils::FileUtil::writeByteArrayToFile(filePath, content);
}


/* ====================================== *
 *           语音消息类接口实现              *
 * ====================================== */
MessageSpeechLabel::MessageSpeechLabel(const QString& fileId, const QByteArray& content, bool isLeft)
    : fileId(fileId), content(content), isLeft(isLeft)
{
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    QFont font;
    font.setFamily("微软雅黑");
    font.setPixelSize(16);

    label = new QLabel(this);
    label->setText("[语音]");
    label->setFont(font);
    label->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
    this->label->setWordWrap(true);
    this->label->setStyleSheet("QLabel { padding: 0 10px; line-height: 1.2; background-color: transparent; }");

    if(content.isEmpty()) {
        model::DataCenter* dataCenter = model::DataCenter::getInstance();
        connect(dataCenter, &model::DataCenter::getSingleFileDone, this, &MessageSpeechLabel::getSingleFileDoneHandle);
        dataCenter->getSingleFileAsync(fileId);
    } else {
        this->loadContentDone = true;
    }
}

void MessageSpeechLabel::paintEvent(QPaintEvent *event)
{
    (void)event;

    QObject* obj = this->parent();
    if(!obj->isWidgetType()) return;

    // 1-1 设定实际每一行的数据宽度 realLineWidget
    QWidget* parent = dynamic_cast<QWidget*>(obj);
    int realWidget = parent->width() * 0.6;

    QFontMetrics metrics(label->font());
    // 1-2 全部数据所需的宽度
    int textTotalWight = metrics.horizontalAdvance(label->text());
    // 1-3 全部数据 + 内边距 需要的行数
    int needLineCount = (textTotalWight / (realWidget - 40)) + 1;
    if(textTotalWight + 30 < realWidget) {
        // 加上左右边距后还是比设定的最大宽度小, 直接置为实际需要的宽度
        realWidget = textTotalWight + 30;
    }
    // 1-4 根据行数，算出的行高(含边距)
    int realHeight = needLineCount * (label->font().pixelSize() * 1.2) + 20;
    if(needLineCount > 1) realHeight += 10;

    // 2. 绘画消息背景ui
    QPainter painter(this);
    QPainterPath path;
    painter.setRenderHint(QPainter::Antialiasing);      // 设置抗锯齿
    if (isLeft) {
        painter.setPen(QPen(QColor(255, 255, 255)));
        painter.setBrush(QColor(255, 255, 255));

        // 绘画一个矩形: 起始坐标, 绘画的宽度*高度, 圆角的幅度
        painter.drawRoundedRect(10, 0, realWidget, realHeight, 10, 10);
        path.moveTo(10, 15);
        path.lineTo(0, 20);     // 从(10, 15)向(0, 20)画一条线
        path.lineTo(10, 25);    // 从(0, 20)向(10, 25)画一条线
        path.closeSubpath();    // 闭合绘画的图形
        painter.drawPath(path);

        label->setGeometry(10, 0, realWidget, realHeight);   // 正文数据的位置
    } else {
        painter.setPen(QPen(QColor(137, 217, 97)));
        painter.setBrush(QColor(137, 217, 97));

        // 矩形左上角、右上角的横坐标位置
        int leftTopPos = this->width() - realWidget - 10;     // 10宽度留给箭头ui
        int rightTopPos = this->width() - 10;
        painter.drawRoundedRect(leftTopPos, 0, realWidget, realHeight, 10, 10);
        path.moveTo(rightTopPos, 15);
        path.lineTo(rightTopPos + 10, 20);
        path.lineTo(rightTopPos, 25);
        path.closeSubpath();
        painter.drawPath(path);

        label->setGeometry(leftTopPos, 0, realWidget, realHeight);
    }

    // 3. 矫正父元素的高度(需要包含除正文外的其它数据高度)
    parent->setFixedHeight(realHeight + 50);
}

void MessageSpeechLabel::mousePressEvent(QMouseEvent* event)
{
    if(event->button() == Qt::LeftButton) {
        if(!this->loadContentDone) {
            Toast::showMessage("数据尚未加载完毕, 请稍后重试");
            return;
        }
        SpeechRecorder* speechRecorder = SpeechRecorder::getInstance();
        connect(speechRecorder, &SpeechRecorder::speechPlayDone, this, &MessageSpeechLabel::speechPlayDoneHandle, Qt::UniqueConnection);
        speechRecorder->startPlay(content);
        this->label->setText("播放中...");
    }
}

void MessageSpeechLabel::contextMenuEvent(QContextMenuEvent* event)
{
    QMenu* menu = new QMenu(this);
    QAction* action = menu->addAction("语音转文字");
    connect(action, &QAction::triggered, this, [=](){
        model::DataCenter* dataCenter = model::DataCenter::getInstance();
        connect(dataCenter, &model::DataCenter::speechConvertTextDone, this, &MessageSpeechLabel::speechConvertTextDoneHandle, Qt::UniqueConnection);
        dataCenter->speechConvertTextAsync(fileId, content);
    });

    // 此处的模态对话框会在用户操作之前阻塞
    menu->exec(event->globalPos());
    menu->deleteLater();
}

void MessageSpeechLabel::getSingleFileDoneHandle(const QString& fileId, const QByteArray& fileContent)
{
    if(this->fileId != fileId) {
        return;
    }
    this->content = fileContent;
    this->loadContentDone = true;
}

void MessageSpeechLabel::speechPlayDoneHandle()
{
    this->label->setText("[语音]");
}

void MessageSpeechLabel::speechConvertTextDoneHandle(const QString& fileId, const QString& result)
{
    if(this->fileId != fileId) {
        return;
    }
    this->label->setText("[语音转文字] " + result);
    this->update();
}

